//
//  PNetwork.m
//  iPiano
//
//  Created by wuxinting on 16/1/13.
//  Copyright © 2016年 wuxinting. All rights reserved.
//

#import "PNetwork.h"
#import "AFNetworking.h"
#import "FDiskCache.h"

@implementation PNetworkFile

+ (NSString *)typeString:(PNetworkFileType)type {
    switch (type) {
        case PNetworkFileImagePNG:
            return @"image/png";
            break;
        case PNetworkFileImageJPG:
            return @"image/jpg";
            break;
        case PNetworkFileImageJPEG:
            return @"image/jpeg";
            break;
        default:
            break;
    }
    return @" ";
}

+ (instancetype)initWithFilePath:(NSURL *)filePath {
    PNetworkFile * nwf = [[PNetworkFile alloc] init];
    nwf.filePath = filePath;
    return nwf;
}

+ (instancetype)initWithFileData:(NSData *)fileData andFileName:(NSString *)fileName andType:(PNetworkFileType)type {
    PNetworkFile * nwf = [[PNetworkFile alloc] init];
    nwf.fileData = fileData;
    nwf.fileName = fileName;
    nwf.fileType = type;
    return nwf;
}

@end

#pragma mark - PNetwork
@interface PNetwork ()

@property (nonatomic, strong) NSURLSessionConfiguration *sessionConfig;

@property (nonatomic, strong) AFURLSessionManager *sessionManager;

@property (nonatomic, strong) AFHTTPSessionManager *httpManager;

@property (nonatomic, strong) AFJSONRequestSerializer *afJsonRequest;

@property (nonatomic, strong) AFHTTPRequestSerializer *afHttpRequest;

@end

@implementation PNetwork

DEF_SINGLETON(PNetwork)

- (instancetype)init {
    if (self = [super init]) {
        _headers = [NSMutableDictionary dictionary];
    }
    return self;
}

// 同步GET Do not use
- (NSURLResponse*)getSync:(NSURL*)url andParams:(NSDictionary*)params {
    // Not support
    return nil;
}

// 异步GET
- (BOOL)get:(NSURL*)url andParams:(NSDictionary*)params completionHandler:(PNetworkCompleteHandler)handler {
    NSURLRequest *request = [self.afHttpRequest requestWithMethod:@"GET" URLString:url.absoluteString parameters:params error:nil];
    
    NSURLSessionDataTask *dataTask = [self.sessionManager dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        BOOL needCache = [[params objectForKey:PNetworkParamKeyCache] boolValue];
        if (handler) {
            error = [self rebuildError:error andResponse:responseObject];
            if (needCache && error) {
                FDiskCache *cache = [FDiskCache cacheForKey:url.path];
                responseObject = [cache peek].object;
            }
            
            handler(response, responseObject, error);
            
            if (needCache && !error) {
                FDiskCache *cache = [FDiskCache cacheForKey:url.path];
                [cache pop];
                [cache push:responseObject];
                [cache flush];
            }
        }
    }];
    
    [dataTask resume];
    return YES;
}

// 同步POST Do not use
- (NSURLResponse*)postSync:(NSURL*)url andParams:(NSDictionary*)params {
    return nil;
}

// 异步POST
- (BOOL)post:(NSURL*)url andParams:(NSDictionary*)params completionHandler:(PNetworkCompleteHandler)handler {
#ifdef DEBUG
    NSLog(@"URL: %@, Params: %@", url, params.jk_JSONString);
#endif
    for (NSString * key in self.headers) {
        [self.afJsonRequest setValue:[self.headers objectForKey:key] forHTTPHeaderField:key];
    }
    
    NSError * error;
    NSURLRequest *request = [self.afJsonRequest requestWithMethod:@"POST" URLString:url.absoluteString parameters:params error:&error];
    if (error) {
        return NO;
    }
    
    NSURLSessionDataTask *dataTask = [self.sessionManager dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        if (handler) {
            error = [self rebuildError:error andResponse:responseObject];
            handler(response, responseObject, error);
        }
    }];
    [dataTask resume];
    return YES;
}

// 上传文件
- (BOOL)upload:(NSURL*)url andFilePath:(NSURL*)path andParams:(NSDictionary*)params progressHandler:(PNetworkProcessHandler)progressHandler completionHandler:(PNetworkCompleteHandler)completeHandler {
    for (NSString * key in self.headers) {
        [self.afJsonRequest setValue:[self.headers objectForKey:key] forHTTPHeaderField:key];
    }
    
    NSMutableDictionary<NSString *, NSData *> * attach = [NSMutableDictionary dictionary];
    NSMutableDictionary * normal = [NSMutableDictionary dictionary];
    for (NSString * key in params.allKeys) {
        id v = [params objectForKey:key];
        if ([v isKindOfClass:[NSData class]]) {
            [attach setObject:v forKey:key];
        } else {
            [normal setObject:v forKey:key];
        }
    }
    
    NSMutableURLRequest *request = [self.afJsonRequest multipartFormRequestWithMethod:@"POST" URLString:url.absoluteString parameters:normal constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        [formData appendPartWithFileURL:path name:D_KEY_FILE error:nil];
        for (NSString * k in attach) {
            id v = [attach objectForKey:k];
            if ([v isKindOfClass:[NSData class]]) {
                [formData appendPartWithFileData:v name:k fileName:@"cover.png" mimeType:@"image/png"];
            } else if ([v isKindOfClass:[NSURL class]]) {
                [formData appendPartWithFileURL:v name:k error:nil];
            } else {}
        }
    } error:nil];
    
    NSURLSessionUploadTask *task = [self.sessionManager uploadTaskWithStreamedRequest:request progress:progressHandler completionHandler:completeHandler];
    [task resume];
    return YES;
}

- (BOOL)upload:(NSURL *)url withFilesAndParams:(NSDictionary *)fileAndParams progressHandler:(PNetworkProcessHandler)progressHandler completionHandler:(PNetworkCompleteHandler)completeHandler {
    for (NSString * key in self.headers) {
        [self.afJsonRequest setValue:[self.headers objectForKey:key] forHTTPHeaderField:key];
    }
    
    NSMutableDictionary<NSString *, PNetworkFile *> * attach = [NSMutableDictionary dictionary];
    NSMutableDictionary * normal = [NSMutableDictionary dictionary];
    for (NSString * key in fileAndParams.allKeys) {
        id v = [fileAndParams objectForKey:key];
        if ([v isKindOfClass:[PNetworkFile class]]) {
            [attach setObject:v forKey:key];
        } else {
            [normal setObject:v forKey:key];
        }
    }
    
    NSMutableURLRequest *request = [self.afJsonRequest multipartFormRequestWithMethod:@"POST" URLString:url.absoluteString parameters:normal constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        for (NSString * k in attach) {
            PNetworkFile * file = [attach objectForKey:k];
            if (file.filePath) {
                [formData appendPartWithFileURL:file.filePath name:k error:nil];
            } else {
                [formData appendPartWithFileData:file.fileData name:k fileName:file.fileName mimeType:[PNetworkFile typeString:file.fileType]];
            }
        }
    } error:nil];
    
    NSURLSessionUploadTask *task = [self.sessionManager uploadTaskWithStreamedRequest:request progress:progressHandler completionHandler:completeHandler];
    [task resume];
    return YES;
}

// 下载文件
- (BOOL)download:(NSURL*)url andParams:(NSDictionary*)params progressHandler:(PNetworkProcessHandler)progressHandler atDestination:(PNetworkDestination)destination completionHandler:(PNetworkCompleteHandler)completeHandler {
    NSURLRequest *request = [self.afHttpRequest requestWithMethod:@"POST" URLString:url.absoluteString parameters:params error:nil];
    
    NSURLSessionDownloadTask *task = [self.sessionManager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        progressHandler(downloadProgress);
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        return destination(targetPath, response);
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        completeHandler(response, filePath, error);
    }];
    [task resume];
    return YES;
}

#pragma mark - Private
- (NSError *)rebuildError:(NSError *)error andResponse:(id)responseObject {
    NSString *domain = @"roing";
    if (error && responseObject) {
        NSInteger code = [[responseObject objectForKey:@"code"] integerValue];
        NSString *detail = [responseObject objectForKey:@"detail"];
        error = [NSError errorWithDomain:domain code:code userInfo:@{NSLocalizedDescriptionKey: detail}];
    }
    
    if (error && !responseObject) {
        switch (error.code) {
            case -1009:
                error = [NSError errorWithDomain:domain code:error.code userInfo:@{NSLocalizedDescriptionKey: @"请检查网络连接情况"}];
                break;
                
            default:
                break;
        }
    }
    return error;
}

#pragma mark - Getters
- (NSURLSessionConfiguration *)sessionConfig {
    if (!_sessionConfig) {
        _sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
        _sessionConfig.timeoutIntervalForRequest = 5;
    }
    return _sessionConfig;
}

- (AFURLSessionManager *)sessionManager {
    if (!_sessionManager) {
        _sessionManager = [[AFURLSessionManager alloc] initWithSessionConfiguration:self.sessionConfig];
    }
    return _sessionManager;
}

- (AFHTTPSessionManager *)httpManager {
    if (!_httpManager) {
        _httpManager = [AFHTTPSessionManager manager];
    }
    return _httpManager;
}

- (AFJSONRequestSerializer *)afJsonRequest {
    if (!_afJsonRequest) {
        _afJsonRequest = [AFJSONRequestSerializer serializer];
    }
    return _afJsonRequest;
}

- (AFHTTPRequestSerializer *)afHttpRequest {
    if (!_afHttpRequest) {
        _afHttpRequest = [AFHTTPRequestSerializer serializer];
    }
    return _afHttpRequest;
}

@end

const PNetworkParamKey PNetworkParamKeyCache = @"PNetworkParamKeyCache";

#import "PError.h"
const NSInteger NWErrorSuccess = 200;
const NSInteger NWErrorUnknown = -1;
const NSInteger NWErrorDoesNotExist = 601;

NSNotificationName const PNetWorkErrorNotification = @"PNetWorkErrorNotification";
